﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024 LiLong                                                   **
**  This file is part of GnssLogs.                                              **
**                                                                              **
**  GnssLogs is free software: you can redistribute it and/or modify            **
**  it under the terms of the GNU Lesser General Public License as published by **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  GnssLogs is distributed in the hope that it will be useful,                 **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU Lesser General Public License for more details.                         **
**                                                                              **
**  You should have received a copy of the GNU Lesser General Public License    **
**  along with GnssLogs.  If not, see <https://www.gnu.org/licenses/>.          **
**********************************************************************************/
#pragma once

#include "../GSV.h"
#include "Commons.h"

namespace GnssLogs
{
namespace GSVDecoder
{
using namespace tao::pegtl;
using LogHeader = NMEA_TALKER_IDENTIFIER("GSV");
// clang-format off
struct Msgs : seq<digit> {};
struct Msg : seq<digit> {};
struct Sats : plus<digit> {};
struct PRN : seq<digit, digit> {};
struct Elev : seq<opt<one<'-'>>, digit, digit> {};
struct Azimuth : seq<digit, digit, digit> {};
struct SNR : seq<digit, digit> {};
struct Satellite : seq<PRN, Split, Elev, Split, opt<Azimuth>, Split, opt<SNR>, sor<Split, one<'*'>>> {};
using NullSatellite = seq<Split, Split, Split, one<'*'>>;
// clang-format on
using Expression = seq<LogHeader,
                       Split,
                       Msgs,
                       Split,
                       Msg,
                       Split,
                       Sats,
                       Split,
                       sor<NullSatellite, star<Satellite>>,
                       opt<SystemId, one<'*'>>,
                       CheckSum,
                       Tail>;

// clang-format off
template <typename T>
struct Action {};
// clang-format on

template<>
struct Action<LogHeader>
{
    template<typename ParseInput>
    static bool apply(ParseInput& in, GSV::Data& data)
    {
        data.header = std::string(in.begin(), in.size());
        return true;
    }
};

template<>
struct Action<Msgs> : IntHelper<Action<Msgs>, uint8_t>
{
    static inline void setValue(GSV::Data& data, uint8_t value) { data.msgs = value; }
};

template<>
struct Action<Msg> : IntHelper<Action<Msg>, uint8_t>
{
    static inline void setValue(GSV::Data& data, uint8_t value) { data.msg = value; }
};

template<>
struct Action<Sats> : IntHelper<Action<Sats>, uint8_t>
{
    static inline void setValue(GSV::Data& data, uint8_t value) { data.sats = value; }
};

template<>
struct Action<PRN> : IntHelper<Action<PRN>, uint8_t>
{
    static inline void setValue(GSV::Data& data, uint8_t value)
    {
        data.satellites.emplace_back(GSV::Data::Satellite {});
        data.satellites.back().prn = value;
    }
};

template<>
struct Action<Elev> : IntHelper<Action<Elev>, int8_t>
{
    static inline void setValue(GSV::Data& data, int8_t value) { data.satellites.back().elev = value; }
};

template<>
struct Action<Azimuth> : IntHelper<Action<Azimuth>, uint16_t>
{
    static inline void setValue(GSV::Data& data, uint16_t value) { data.satellites.back().azimuth = value; }
};

template<>
struct Action<SNR> : IntHelper<Action<SNR>, uint8_t>
{
    static inline void setValue(GSV::Data& data, uint8_t value) { data.satellites.back().snr = value; }
};

template<>
struct Action<SystemId> : SystemIdHelper<Action<SystemId>>
{
    static inline void setValue(GSV::Data& data, uint8_t value) { data.systemId = value; }
};

template<>
struct Action<CheckSum> : CheckSumHelper<Action<CheckSum>>
{
    static inline void setValue(GSV::Data& data, uint8_t value) { data.checkSum = value; }
};
} // namespace GSVDecoder
} // namespace GnssLogs
